home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / asmbler.arc / NEWCTLT.ASM < prev    next >
Assembly Source File  |  1988-11-19  |  15KB  |  447 lines

  1.         title   CTLT - Control-T Interrupt Handler
  2.         page    60,132
  3.  
  4. ;***********************************************************************
  5. ;
  6. ; This routine works by trapping every interrupt 9 (KB_INT) generated by
  7. ; the keyboard and handled by the IBM BIOS, and after return from  BIOS,
  8. ; inspecting the key which was typed and is now present in the  keyboard
  9. ; ring buffer  in  the BIOS  data  segment (40h).   If  it is  the  user
  10. ; interrupt character (normally a CTL-T), it is removed from the  buffer
  11. ; and a status message is displayed on the console screen.
  12. ;
  13. ;                          ***************
  14. ;                          *** N O T E ***
  15. ;                          ***************
  16. ;
  17. ; This code depends  upon buffer size,  organization, and location,  and
  18. ; pointers thereto,  in  the IBM  BIOS  data segment.   If  a  different
  19. ; keyboard interrupt  handler  is  installed (e.g.  one  that  increases
  20. ; buffer size), this code will probably fail!
  21. ;
  22. ; [02-Aug-84]   Nelson H.F. Beebe, College of Science Computer,
  23. ;               University of Utah, Salt Lake City, UT 84112, USA
  24. ;***********************************************************************
  25.  
  26.         .xlist
  27.         include ascii.inc
  28.         include dos.inc
  29.         .list
  30.  
  31.  
  32. keyvect segment at 0
  33.         org     9h*4                    ; BIOS KB_INT
  34. keyint  label   dword
  35. keyvect ends
  36.  
  37.  
  38. biosdata        segment at 40h
  39.                 org     1ah             ; See p. A-3 of IBM Tech. Ref. Manual
  40. buffer_head     dw      ?               ; pointer to head of keyboard buffer
  41.                                         ; -- address of first available char
  42. buffer_tail     dw      ?               ; pointer to tail of keyboard buffer
  43.                                         ; -- address of next empty slot
  44.                                         ; -- buffer is empty if head=tail
  45. kb_buffer       dw      16 dup (?)      ; room for 15 entries
  46.                 org     $-2
  47. kb_bufend       dw      ?               ; last word in buffer
  48. biosdata        ends
  49.  
  50.  
  51. ;***********************************************************************
  52. ;
  53. ; INIT_CODE - Code to load and initialize the handler.
  54. ; Sets up  DOS  to  keep  all code  before  "LASTONE"  label  safe  from
  55. ; overlaying during system operation.
  56. ;
  57. ;***********************************************************************
  58.  
  59. CODE    SEGMENT PARA
  60.         org     100h                    ; for .COM file
  61.  
  62.         assume  cs:code,ds:code
  63.         assume  es:biosdata
  64.  
  65. TYPE_CHAR PROC  NEAR
  66. ; Type character in AL at the current cursor position using the  current
  67. ; character attribute.  No translation is done, except that BIOS handles
  68. ; CR, LF, BEL, and BS as for a teletype.
  69. ; All registers preserved
  70.  
  71.         push    ax
  72.         push    bx
  73.         push    ax                      ; save extra copy of character
  74.  
  75.         mov     ah,$VIDEO_GETVIDEOSTATE
  76.         int     $VIDEO                  ; get current page in bh
  77.  
  78.         mov     ah,$VIDEO_GETATTRCHAR
  79.         int     $VIDEO                  ; get current attribute in ah
  80.         mov     bl,ah                   ; save current attribute
  81.  
  82.         pop     ax                      ; restore character
  83.         mov     ah,$VIDEO_SETTTY        ; tty output (bl = current attribute)
  84.         int     $VIDEO                  ; character
  85.  
  86.         pop     bx                      ; restore registers
  87.         pop     ax
  88.         ret
  89. TYPE_CHAR ENDP
  90.  
  91.         assume  cs:code,ds:code
  92. TYPE_CRLF PROC   NEAR
  93. ; Type CR LF pair
  94. ; All registers preserved
  95.         push    ax                      ; save registers
  96.  
  97.         mov     al,.CR
  98.         call    TYPE_CHAR
  99.  
  100.         mov     al,.LF
  101.         call    TYPE_CHAR
  102.  
  103.         pop     ax                      ; restore registers
  104.         ret
  105. TYPE_CRLF ENDP
  106.  
  107.         assume  cs:code,ds:code
  108. TYPE_DEC PROC   NEAR
  109. ; Type integer in AX in decimal, BH = fill character, BL = field width
  110. ; BL=0 means minimum field width with no fill
  111. ; All registers preserved
  112.         push    ax                      ; save registers
  113.         push    bx
  114.         push    cx
  115.         push    dx
  116.         push    bp
  117.  
  118.         xor     cx,cx
  119.         mov     cl,bl                   ; minimum field width
  120.  
  121.         mov     bp,ax                   ; save original number
  122.         test    ax,ax                   ; number < 0?
  123.         jge     not_neg                 ; no
  124.         neg     ax                      ; yes, replace by abs(number)
  125.  
  126. not_neg:
  127.         push    EFLAG                   ; mark end of number on stack
  128.  
  129. digit_loop:
  130.         cwd                             ; sign-extend ax into (ax,dx)
  131.         dec     cx                      ; reduce field width
  132.         div     TEN                     ; number/10 to ax, remainder to dx
  133.         add     dx,"0"                  ; convert to ASCII
  134.         push    dx                      ; save digit
  135.         test    ax,ax                   ; zero yet?
  136.         ja      digit_loop              ; no, keep dividing
  137.  
  138.         mov     dx,bp                   ; original number
  139.         test    dx,dx                   ; number < 0?
  140.         jge     digit_plus              ; no
  141.  
  142.         dec     cx                      ; yes, reduce field width
  143.         cmp     bh," "                  ; blank fill?
  144.         jne     digit_plus              ; no
  145.         mov     al,"-"                  ; yes, save immediate leading
  146.         push    ax                      ; minus sign
  147.  
  148. digit_plus:
  149.         test    cx,cx                   ; remaining count > 0?
  150.         jle     digit_sign              ; yes, fill unnecessary
  151.  
  152.         mov     al,bh                   ; fill character
  153.  
  154. digit_fill:
  155.         push    ax                      ; save fill character
  156.         loop    digit_fill              ; loop until cx=0
  157.  
  158. digit_sign:
  159.         mov     dx,bp                   ; original number
  160.         test    dx,dx                   ; number < 0?
  161.         jge     digit_type              ; no
  162.         cmp     bh," "                  ; blank fill?
  163.         je      digit_type              ; yes, already saved sign
  164.         mov     al,"-"                  ; no, save sign
  165.         push    ax
  166.  
  167. digit_type:
  168.         pop     ax                      ; digit
  169.         cmp     ax,EFLAG                ; end of number yet?
  170.         je      digit_done              ; yes
  171.         call    TYPE_CHAR               ; type it
  172.         jmp     short digit_type        ; and go for next digit
  173.  
  174. digit_done:
  175.         pop     bp                      ; restore registers
  176.         pop     dx
  177.         pop     cx
  178.         pop     bx
  179.         pop     ax
  180.         ret                             ; return to caller
  181.  
  182. EFLAG   dw      -1                      ; special end-of-number flag
  183. TEN     dw      10
  184. TYPE_DEC ENDP
  185.  
  186.         assume  cs:code,ds:code
  187. TYPE_HEX PROC   NEAR
  188. ; Type byte in AL as two-character hexadecimal
  189. ; All registers preserved
  190.         push    cx              ; save registers
  191.         push    bx
  192.         push    ax
  193.  
  194.         push    ax              ; save ax
  195.         mov     bh,0            ; clear top of bx
  196.         mov     cl,4            ; shift count
  197.         mov     bl,al           ; byte to print
  198.         shr     bl,cl           ; left nibble
  199.         mov     al,hex_chars[bx]; get character
  200.         call    TYPE_CHAR       ; and print it
  201.         pop     bx              ; restore ax into bx
  202.  
  203.         and     bx,0fh          ; left nibble
  204.         mov     al,hex_chars[bx]; get character
  205.         call    TYPE_CHAR       ; and print it
  206.  
  207.         pop     ax              ; restore registers
  208.         pop     bx
  209.         pop     cx
  210.         ret
  211.  
  212. hex_chars db    "0123456789ABCDEF"
  213. TYPE_HEX ENDP
  214.  
  215.         assume  cs:code,ds:code
  216. TYPE_STRING PROC  NEAR
  217. ; Type NUL-terminated string pointed to by DS:SI (the NUL is not typed).
  218. ; All registers preserved
  219.         push    ax
  220.         push    dx
  221.         push    si
  222.  
  223.         cld                             ; read string forward
  224. msg_loop:
  225.         lodsb                           ; byte to al, increment si
  226.         test    al,al                   ; message byte = 0?
  227.         jz      done_string             ; yes, all done
  228.         call    TYPE_CHAR               ; no, type it
  229.         jmp     short msg_loop          ; keep printing
  230.  
  231. done_string:
  232.         pop     si
  233.         pop     dx
  234.         pop     ax
  235.         ret
  236. TYPE_STRING ENDP
  237.  
  238.         assume  cs:code,ds:code
  239. TYPE_TIME PROC  NEAR
  240. ; Type the current time as hh:mm:ss
  241. ; All registers preserved
  242.         push    ax                      ; save registers
  243.         push    bx
  244.         push    cx
  245.         push    dx
  246.  
  247.         mov     ah,$DOS_GETTIME
  248.         int     $DOS
  249.         xor     ah,ah                   ; clear top of ax
  250.         mov     al,ch                   ; hours
  251.         mov     bl,0                    ; field width=0
  252.         mov     bh," "                  ; fill character
  253.         call    TYPE_DEC                ; type hh
  254.  
  255.         mov     al,":"
  256.         call    TYPE_CHAR
  257.  
  258.         mov     al,cl                   ; minutes
  259.         mov     bl,2                    ; field width
  260.         mov     bh," "                  ; fill character
  261.         call    TYPE_DEC                ; type mm
  262.  
  263.         mov     al,":"
  264.         call    TYPE_CHAR
  265.  
  266.         mov     al,dh                   ; seconds
  267.         mov     bl,2                    ; field width
  268.         mov     bh," "                  ; fill character
  269.         call    TYPE_DEC                ; type ss
  270.  
  271.         mov     al,"."
  272.         call    TYPE_CHAR
  273.  
  274.         mov     al,dl                   ; centiseconds
  275.         mov     bl,2                    ; field width
  276.         mov     bh," "                  ; fill character
  277.         call    TYPE_DEC                ; now have typed "hh:mm:ss.cc"
  278.  
  279.         pop     dx                      ; restore registers
  280.         pop     cx
  281.         pop     bx
  282.         pop     ax
  283.         ret                             ; return to caller
  284. TYPE_TIME ENDP
  285.  
  286.         assume  cs:code,ds:code
  287.         assume  es:biosdata
  288.  
  289. KEY     PROC    NEAR
  290. start:
  291.         jmp     init_code               ; done only once at startup
  292.  
  293. key_call:                               ; Far JMP to keyboard interrupt
  294.         jmp     far ptr es:0            ; filled in at runtime
  295. ;       db      0eah
  296. ;       dw      0,0
  297.  
  298.  
  299. old_ip  equ     [bp+2]                  ; bp = entry_sp-2
  300. old_cs  equ     [bp+4]
  301. old_fl  equ     [bp+6]
  302.  
  303. key_rtne:
  304.         sti                             ; turn interrupts back on
  305.  
  306.         push    ax                      ; save registers
  307.         push    bx
  308.         push    cx
  309.         push    dx
  310.         push    bp
  311.         push    ds
  312.         push    es
  313.         push    di
  314.         push    si
  315.  
  316.         mov     bx,cs
  317.         mov     ds,bx                   ; establish local DS = CS
  318.  
  319.         mov     bx,biosdata
  320.         mov     es,bx                   ; establish ES -> BIOSDATA
  321.  
  322. ; First call original KB_INT BIOS code to actually retrieve the character
  323. ; over the keyboard port and do its massive amount of bookkeeping
  324.  
  325.         pushf                           ; flags to fake interrupt call
  326.         mov     bx,offset key_call+1    ; get address of ROM code for keyboard
  327.         call    dword ptr [bx]          ; call ROM code
  328.  
  329. ;-----------------------------------------------------------------------
  330. ; enter critical section -- no interrupts allowed until character retrieved
  331. ; and buffer pointers updated
  332.  
  333.         cli                             ; interrupts off while char retrieved
  334.         mov     bx,es:buffer_tail       ; next available slot in buffer
  335.         dec     bx                      ; backup 2 bytes
  336.         dec     bx
  337.         cmp     bx,offset kb_buffer     ; backed up before start?
  338.         jae     nowrap                  ; no
  339.         mov     bx,offset kb_bufend     ; yes, move to end of buffer
  340. nowrap:
  341.         mov     ax,es:[bx]              ; char in al, scan code in ah
  342.  
  343.         cmp     al,.ctlt                ; CTL-T?
  344.         jne     done                    ; no
  345.  
  346.         mov     es:buffer_tail,bx       ; remove last character (the CTL-T)
  347.         sti                             ; interrupts back on
  348.  
  349. ; end critical section
  350. ;-----------------------------------------------------------------------
  351.  
  352.         call    TYPE_TIME
  353.  
  354.         mov     si,offset csip_msg
  355.         call    TYPE_STRING
  356.  
  357.         mov     al,old_cs+1
  358.         call    TYPE_HEX
  359.  
  360.         mov     al,old_cs
  361.         call    TYPE_HEX
  362.  
  363.         mov     al,":"
  364.         call    TYPE_CHAR
  365.  
  366.         mov     al,old_ip+1
  367.         call    TYPE_HEX
  368.  
  369.         mov     al,old_ip
  370.         call    TYPE_HEX
  371.  
  372.         mov     si,offset flags_msg
  373.         call    TYPE_STRING
  374.  
  375.         mov     al,old_fl+1
  376.         call    TYPE_HEX
  377.  
  378.         mov     al,old_fl
  379.         call    TYPE_HEX
  380.  
  381.         call    TYPE_CRLF
  382.  
  383. done_int:
  384.         pop     si                      ; restore saved registers
  385.         pop     di
  386.         pop     es
  387.         pop     ds
  388.         pop     bp
  389.         pop     dx
  390.         pop     cx
  391.         pop     bx
  392.         pop     ax
  393.         iret                            ; return from interrupt
  394.  
  395. csip_msg db     " CS:IP ",0
  396. flags_msg db    " Flags ",0
  397.  
  398. KEY     ENDP
  399.  
  400.  
  401. lastone:        ; all code after this label is freed to DOS after
  402.                 ; program initialization
  403.  
  404. copyrt  db      'CONTROL-T Handler -- Version 1.0 -- Public Domain 1984'
  405.         db      .CR,.LF
  406.         db      'Nelson H.F. Beebe, University of Utah, Salt Lake City, '
  407.         db      'UT 84112, USA'
  408.         db      .CR,.LF,0
  409.  
  410.         assume  cs:code,ds:code
  411.         assume  es:keyvect
  412. INIT_CODE PROC NEAR
  413.  
  414. ; Initialize KEYBOARD interrupt system
  415.  
  416. ;-----------------------------------------------------------------------
  417. ; enter critical section -- no interrupts while adjusting interrupt vector
  418. ;
  419.         cli                             ; interrupts off
  420.         mov     ax,keyvect              ; Get address to interrupt vector
  421.         mov     es,ax                   ; Save in ES
  422.         mov     ax,es:keyint            ; Get address to interrupt routine
  423.         mov     bx,offset key_call+1    ; Address to place to save vector
  424.         mov     [bx],ax                 ; Save interrupt address
  425.         mov     ax,es:keyint[2]         ; Get interrupt segment for routine
  426.         mov     [bx+2],ax               ; Save it too
  427.         mov     es:keyint,offset key_rtne       ; Now, replace with own address
  428.         mov     ax,cs                   ; Save segment in interrupt vector
  429.         mov     es:keyint[2],ax
  430.         sti                             ; interrupts back on
  431.  
  432. ; end critical section
  433. ;-----------------------------------------------------------------------
  434.  
  435. ; Now, print out acknowledgement to user monitor and exit
  436.  
  437.         mov     ax,cs                   ; Set up segment to this routine
  438.         mov     ds,ax
  439.         mov     si,offset copyrt        ; Now, print out copyright message
  440.         call    TYPE_STRING
  441.         mov     dx,offset lastone       ; Save all code up to "LASTONE" label
  442.         int     27h                     ; No return needed
  443.  
  444. INIT_CODE ENDP
  445. CODE    ENDS
  446.         END     START
  447.